package org.fastiot.protocol.group

import grails.databinding.BindUsing
import org.fastiot.protocol.codec.BitOutputStream
import org.fastiot.protocol.codec.BitSource

/**
 * 键值对编组（单键单值/单键多值）
 */
class KeyValue implements Groupable {

    static enum Model {
        SingleValue(0), MultiValued(1)
        final int value

        private Model(int value) { this.value = value }

        static Model byValue(int val) {
            values().find { it.value == val } ?:
                    { throw new IllegalArgumentException("KeyValue\$Model ${val} not found") }()
        }
    }

    /**
     * 隶属（结构/编组）/父类型
     */
    @BindUsing({ obj, source ->
        Affiliation.byValue(Integer.parseInt(source["parentType"] as String))
    })
    Affiliation parentType

    /**
     * 隶属（结构/编组）代码
     */
    Integer parentCode

    /**
     * 隶属（结构/编组）代码（Hex）
     */
    String hexParentCode

    /**
     * code for key
     */
    Integer code
    String hexCode

    /**
     * （编组）标识符
     */
    String dataIdentifier

    /**
     * （编组）名称
     */
    String name
    /**
     * （编组）模型
     * 使用单值编组时，分组结构：键 + 值；
     * 使用多值编组时，分组结构：键 + 值数 + 值 x 值数，其中值数的长度固定，由系统统一配置。
     */
    @BindUsing({ obj, source ->
        Model.byValue(Integer.parseInt(source["model"] as String))
    })
    Model model
    /**
     * （基础）规则代码
     */
    String ruleCode

    boolean enabled = false

    String remark
    Date dateCreated
    Date lastUpdated

    static transients = ['hexParentCode', 'hexCode']

    static constraints = {
        parentType(nullable: false, inList: Affiliation.values().toList())
        parentCode(nullable: false)
        hexParentCode(nullable: false, matches: /[a-fA-F0-9]+/)
        code(nullable: false, min: 0)
        hexCode(blank: false, matches: /[a-fA-F0-9]+/)
        dataIdentifier(blank: false)
        name(blank: false)
        model(nullable: false, inList: Model.values().toList())
        ruleCode(blank: true, unique: [ "parentType", "parentCode" ], matches: /[a-zA-Z0-9]+/)
        enabled(blank: false)
        remark(nullable: true, widget: 'textarea')
    }

    static mapping = {
        remark type: 'text'
    }

    def beforeValidate() {
        if (hexParentCode && !parentCode)
            parentCode = Integer.parseInt(hexParentCode, 16)

        if (hexCode && !code)
            code = Integer.parseInt(hexCode, 16)
    }

    def afterLoad() {
        if (code)
            hexCode = Integer.toHexString(code)

        if (parentCode)
            hexParentCode = Integer.toHexString(parentCode)
    }

    @Override
    void decode(final BitSource bitSource, final Map contents) {
        throw new UnsupportedOperationException("The method is not implemented")
    }

    @Override
    void encode(final BitOutputStream bitOutput, final Map contents) {
        throw new UnsupportedOperationException("The method is not implemented")
    }
}
